package cn.com.greatwall.system.modules.security.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import cn.com.greatwall.common.annotation.AnonymousAccess;
import cn.com.greatwall.common.utils.SpringContextHolder;
import cn.com.greatwall.common.utils.enums.RequestMethodEnum;
import cn.com.greatwall.system.modules.security.config.bean.SecurityProperties;
import cn.com.greatwall.system.modules.security.security.JwtAccessDeniedHandler;
import cn.com.greatwall.system.modules.security.security.JwtAuthenticationEntryPoint;
import cn.com.greatwall.system.modules.security.security.SecurityAuthenticationProvider;
//import cn.com.greatwall.system.modules.security.security.TokenConfigurer;
//import cn.com.greatwall.system.modules.security.security.TokenProvider;
//import cn.com.greatwall.system.modules.security.security.TokenProvider;
import cn.com.greatwall.system.modules.security.service.OnlineUserService;
import cn.com.greatwall.system.modules.security.service.UserCacheClean;
import cn.com.greatwall.system.modules.security.service.UserDetailsServiceImpl;
import lombok.RequiredArgsConstructor;

/**
 * @Author herw
 * @Time 2020-06-21 9:33:58 PM
 * @Version 1.0
 * @Description:
 */
//@Configuration
//@EnableWebSecurity
////@RequiredArgsConstructor
//@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//  @Autowired
//  private UserDetailsServiceImpl userDetailService; 
//  
//  public SecurityConfig(UserDetailsServiceImpl userDetailService) {
//      this.userDetailService = userDetailService;
//  }
//  
//  /**
//   * 让Security 忽略这些url，不做拦截处理
//   *
//   * @param
//   * @throws Exception
//   */
//  @Override
//  public void configure(WebSecurity web) throws Exception {
//      web.ignoring().antMatchers
//              ("/swagger-ui.html/**", "/webjars/**",
//                      "/swagger-resources/**", "/v2/api-docs/**",
//                      "/swagger-resources/configuration/ui/**","/statics/**","/swagger-resources/configuration/security/**",
//                      "/images/**");
//  }
//  
//  @Override
//  public void configure(AuthenticationManagerBuilder auth) throws Exception {
//      auth.userDetailsService(userDetailService);
//  }
//  
//  @Override
//  protected void configure(HttpSecurity http) throws Exception {
//
////      BootBaseLoginProperties base = properties.getBaseLogin();
////      BootSmsLoginProperties sms = properties.getSmsLogin();
//      http
//              // http security 要拦截的url，这里这拦截，oauth2相关和登录登录相关的url，其他的交给资源服务处理
//              .requestMatchers()
//              .antMatchers( "/oauth/**","/auth/login",
//                      "/authentication/base","/authentication/mobile")
//              .and()
//              .authorizeRequests()
//              // 自定义页面或处理url是，如果不配置全局允许，浏览器会提示服务器将页面转发多次
//              .antMatchers("/auth/login",
//                      "/authentication/base","/authentication/mobile")
//              .permitAll()
//              .anyRequest()
//              .authenticated();
//
//      // 表单登录
//      http.formLogin()
//              // 请求 {用户名} 参数名称
//              .usernameParameter("username")
//              // 请求 {密码} 参数名
//              .passwordParameter("password")
//              // 登录页面
//              .loginPage("/auth/login")
//              // 登录处理url
//              .loginProcessingUrl("/authentication/base");
//
//      http.httpBasic().disable();
//
//
//      // 用户密码验证之前校验验证码
////      http.addFilterBefore(pictureCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
//
//  }
//
//
//  @Override
//  @Bean
//  public AuthenticationManager authenticationManagerBean() throws Exception {
//      return super.authenticationManagerBean();
//  }
//
//  @Bean
//  public PasswordEncoder passwordEncoder() {
//      return new BCryptPasswordEncoder();
//  }
//  
  
  
  
  
  
  
    
    
//    private final TokenProvider tokenProvider;
//    private final CorsFilter corsFilter;
//    private final JwtAuthenticationEntryPoint authenticationErrorHandler;
//    private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
//    private final ApplicationContext applicationContext;
//    private final SecurityProperties properties;
//    private final OnlineUserService onlineUserService;
//    private final UserCacheClean userCacheClean;
//    private final UserDetailsServiceImpl userDetailsServiceImpl;

    @Autowired
    private SecurityAuthenticationProvider provider;
    @Autowired
    private UserDetailsServiceImpl userDetailService;

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        // 去除 ROLE_ 前缀
        return new GrantedAuthorityDefaults("");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 密码加密方式
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
//    
////    @Bean
////    public AuthenticationProvider authenticationProvider() {
////        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
////        daoAuthenticationProvider.setUserDetailsService(userDetailsServiceImpl);
////        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
////        return daoAuthenticationProvider;
////    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 将 check_token 暴露出去，否则资源服务器访问时报 403 错误
        web.ignoring().antMatchers("/oauth/check_token");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // http security 要拦截的url，这里这拦截，oauth2相关和登录登录相关的url，其他的交给资源服务处理
                .requestMatchers().antMatchers("/oauth/**", "/auth/login", "/authentication/base").and()
                .authorizeRequests()
                // 自定义页面或处理url是，如果不配置全局允许，浏览器会提示服务器将页面转发多次
                .antMatchers("/auth/login", "/authentication/base").permitAll().anyRequest().authenticated();

// 表单登录
        http.formLogin()
                // 请求 {用户名} 参数名称
                .usernameParameter("username")
                // 请求 {密码} 参数名
                .passwordParameter("password")
                // 登录页面
                .loginPage("/auth/login")
                // 登录处理url
                .loginProcessingUrl("/authentication/base");

        http.httpBasic().disable();

//        http.csrf().ignoringAntMatchers("/oauth/authorize", "/oauth/token", "/oauth/rest_token");
//
//        http.authorizeRequests()
//                // permitAll() 的URL路径属于公开访问，不需要权限
//                .antMatchers("/resources/**").permitAll()
//                .antMatchers("/static/**").permitAll()
//                .antMatchers("/oauth/rest_token*").permitAll()
//                .antMatchers("/login*").permitAll()
//                .antMatchers(HttpMethod.GET, "/login*").anonymous()
//                .anyRequest().authenticated()
//                .and()
//                .formLogin()
//                .loginPage("/login.html")
//                .loginProcessingUrl("/login")
////                .failureUrl("/login?error=1")
////                .usernameParameter("oidc_user")
////                .passwordParameter("oidcPwd")
//                .permitAll()
//                .and()
//                .logout()
//                .invalidateHttpSession(true)
//                .clearAuthentication(true)
////                .logoutUrl("/signout")
//                .deleteCookies("JSESSIONID")
//                .logoutSuccessUrl("/")
//                .and()
//                .exceptionHandling();
//
////        http.authenticationProvider(authenticationProvider());
    }

    /**
     * 自定义验证逻辑
     * 
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.authenticationProvider(provider);
        auth.userDetailsService(userDetailService);
    }

//    /**
//     * 使用 permitAll() 方法所有人都能访问，包括带上 token 访问<br/>
//     * 使用 anonymous() 所有人都能访问，但是带上 token 访问后会报错
//     */
//    @Override
//    protected void configure(HttpSecurity httpSecurity) throws Exception {
//        // 搜寻匿名标记 url： @AnonymousAccess
//        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = ((RequestMappingHandlerMapping) applicationContext
//                .getBean("requestMappingHandlerMapping")).getHandlerMethods();
//        // 获取匿名标记
//        Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
//        httpSecurity.csrf().ignoringAntMatchers("/oauth/authorize", "/oauth/token", "/oauth/rest_token");
//        httpSecurity
//                // 禁用 CSRF
//                .csrf().disable().addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
//                // 授权异常
//                .exceptionHandling().authenticationEntryPoint(authenticationErrorHandler)
//                .accessDeniedHandler(jwtAccessDeniedHandler)
//                // 防止iframe 造成跨域
//                .and().headers().frameOptions().disable()
//                // 不创建会话
//                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
//                .authorizeRequests()
//                // 静态资源等等
//                .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/webSocket/**")
//                .permitAll()
//                // swagger 文档
//                .antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources/**").permitAll()
//                .antMatchers("/webjars/**").permitAll().antMatchers("/*/api-docs").permitAll()
//                // 文件
//                .antMatchers("/avatar/**").permitAll().antMatchers("/file/**").permitAll()
//                // 阿里巴巴 druid
//                .antMatchers("/druid/**").permitAll()
//                // Oauth2.0
//                .antMatchers("/oauth/**").permitAll()
//                // 放行OPTIONS请求
//                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
//                // 自定义匿名访问所有url放行：允许匿名和带Token访问，细腻化到每个 Request 类型
//                // GET
//                .antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0]))
//                .permitAll()
//                // POST
//                .antMatchers(HttpMethod.POST,
//                        anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0]))
//                .permitAll()
//                // PUT
//                .antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0]))
//                .permitAll()
//                // PATCH
//                .antMatchers(HttpMethod.PATCH,
//                        anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0]))
//                .permitAll()
//                // DELETE
//                .antMatchers(HttpMethod.DELETE,
//                        anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0]))
//                .permitAll()
//                // 所有类型的接口都放行
//                .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
//                // 所有请求都需要认证
//                .anyRequest().authenticated().and().apply(securityConfigurerAdapter());
//    }

//    private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
//        Map<String, Set<String>> anonymousUrls = new HashMap<>(6);
//        Set<String> get = new HashSet<>();
//        Set<String> post = new HashSet<>();
//        Set<String> put = new HashSet<>();
//        Set<String> patch = new HashSet<>();
//        Set<String> delete = new HashSet<>();
//        Set<String> all = new HashSet<>();
//        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
//            HandlerMethod handlerMethod = infoEntry.getValue();
//            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
//            if (null != anonymousAccess) {
//                List<RequestMethod> requestMethods = new ArrayList<>(
//                        infoEntry.getKey().getMethodsCondition().getMethods());
//                RequestMethodEnum request = RequestMethodEnum.find(
//                        requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
//                switch (Objects.requireNonNull(request)) {
//                case GET:
//                    get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                case POST:
//                    post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                case PUT:
//                    put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                case PATCH:
//                    patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                case DELETE:
//                    delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                default:
//                    all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                    break;
//                }
//            }
//        }
//        anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
//        anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
//        anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
//        anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
//        anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
//        anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
//        return anonymousUrls;
//    }

//    private TokenConfigurer securityConfigurerAdapter() {
//        return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean);
//    }

//    @Bean
//    public SpringContextHolder springContextHolder() {
//        return new SpringContextHolder();
//    }
}
